<template>
    <MyArticle class="readingNotes-webgl-06" title="WebGL学习笔记之六：进入三维世界" date="2021年05月19日">
        <div class="_article-content">
            <p>将讲解视图矩阵、投影矩阵；学习如何控制三维可视空间，处理物体的前后关系，以及绘制三维的立方体。</p>
            <h3 class="title">视图矩阵</h3>
            <p><strong>立方体由三角形构成。</strong>绘制三维物体时，需要考虑它们的深度信息。</p>
            <p>视图矩阵(view matrix)由以下三个矢量构成：</p>
            <p><strong>视点</strong>：观察者所处的位置。视线的起点，坐标(eyeX, eyeY, eyeZ)表示。</p>
            <p><strong>观察目标点</strong>：被观察目标所在的点。视线从视点出发，穿过观察目标点并继续延伸。观察目标点是一个点，而不是视线方向，只有同时知道观察目标点和视点，才能算出视线方向。坐标用(atX, atY, atZ)表示。</p>
            <p><strong>上方向</strong>：最终绘制在屏幕上的影像中的向上的方向。这个方向将观察者固定住了。用坐标(upX, upY, upZ)表示。</p>
            <p>使用以下方法设置视图矩阵：</p>
            <pre><code>Matrix4.setLookAt(eyeX, eyeY, eyeZ, atX, atY, atZ, upX, upY, upZ)
// 观察者的默认状态是：视点为系统原点(0,0,0)；视线为Z轴负方向，观察点为(0,0,-1)；上方向为Y轴负方向(0,1,0)</code></pre>
            <canvas ref="canvasRef0" v-show="!img0" class="webgl-canvas"></canvas>
            <img :src="img0" v-show="img0" class="webgl-canvas"/>
            <pre><code>// 视图矩阵为：
viewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1.0, 0)

// 点坐标与颜色值
const datas = new Float32Array([
    0.0, 0.5, -0.4, 0.4, 1.0, 0.4,
    -0.5, -0.5, -0.4, 0.4, 1.0, 0.4,
    0.5, -0.5, -0.4, 1.0, 0.4, 0.4,

    0.5, 0.4, -0.2, 1.0, 0.4, 0.4,
    -0.5, 0.4, -0.2, 1.0, 1.0, 0.4,
    0.0, -0.6, -0.2, 1.0, 1.0, 0.4,

    0.0, 0.5, 0.0, 0.4, 0.4, 1.0,
    -0.5, -0.5, 0.0, 0.4, 0.4, 1.0,
    0.5, -0.5, 0.0, 1.0, 0.4, 0.4
])

// 顶点着色器
const VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    uniform mat4 u_ViewMatrix;
    varying vec4 v_Color;
    void main() {
        gl_Position = u_ViewMatrix * a_Position;
        v_Color = a_Color;
    }
`

// 片元着色器
const FSHADER_SOURCE = `
    precision mediump float;
    varying vec4 v_Color;
    void main() {
        gl_FragColor = v_Color;
    }
`
......
// 设置视图矩阵
const uViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix')
gl.uniformMatrix4fv(uViewMatrix, false, viewMatrix)

gl.clearColor(0.0, 0.0, 0.0, 1.0)
gl.clear(gl.COLOR_BUFFER_BIT)
gl.drawArrays(gl.TRIANGLES, 0, n)</code></pre>
            <p>视图矩阵被传给了顶点着色器，并与顶点坐标相乘。<strong>“根据自定义的观察者状态，绘制观察者看到的景象”与“使用默认的观察状态，但对三维对象进行平移、旋转等变换，再绘制观察者看到的景象”，这两者行为是等价的。</strong></p>
            <pre><code>"从视点看上去"的旋转顶点坐标 = 视图矩阵 * 旋转矩阵 * 原始顶点坐标 = 模型视图矩阵 * 原始顶点坐标
模型视图矩阵 = 视图矩阵 * 模型矩阵</code></pre>
            <p>模型视图矩阵的应用——旋转变换：</p>
            <canvas ref="canvasRef1" v-show="!img1" class="webgl-canvas"></canvas>
            <img :src="img1" v-show="img1" class="webgl-canvas"/>
            <pre><code>const viewMatrix = new Matrix4()
viewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1.0, 0)
const modelMatrix = new CuonMatrix4()
modelMatrix.setRotate(-20, 0, 0, 1) // 旋转矩阵
const modelViewMatrix = viewMatrix.multiply(modelMatrix)</code></pre>
            <p>简写成以下形式也可以：</p>
            <pre><code>const modelViewMatrix = new Matrix4()
modelViewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1.0, 0).rotate(-20, 0, 0, 1)</code></pre>
            <h3 class="title">可视范围</h3>
            <p>当以上三角形旋转至某个位置时，会缺少一部分没显示出来。原因是没有指定<strong>可视范围</strong>，即实际观察得到的区域边界。WebGL只显示可视范围之内的区域。不绘制可视范围之外的对象，是降低程序开销的基本手段。人类能看到眼前范围的东西，水平视角大约200度左右。</p>
            <p>水平视角、重置视角和可视深度，定义了<strong>可视空间</strong>。有两类可视空间，长方体可视空间（盒状空间，由<strong>正射投影</strong>产生）和四棱锥/金字塔可视空间（由<strong>透视投影</strong>产生）。</p>
            <p>盒状可视空间由前后两个矩形表面确定，分别称为<strong>近裁剪面</strong>和<strong>远裁剪面</strong>，前者的四个顶点为(right, top, near)、(left, top, near)、(left, bottom, near)、(right, bottom, near)，而后者的四个顶点为(right, top, far)、(left, top, far)、(left, bottom, far)、(right, bottom, far)。canvas上显示的就是可视空间中物体在近裁剪面的投影。如果裁剪面的宽高比和canvas不一样，那么画面会被按照canvas的宽高比进行压缩，物体会被扭曲显示。</p>
            <p>Matrix4.setOrtho()方法可以用来设置投影矩阵，定义盒状可视空间：</p>
            <pre><code>Matrix4.setOrtho(left, right, bottom, top, near, far)</code></pre>
            <canvas ref="canvasRef2" v-show="!img2" class="webgl-canvas"></canvas>
            <img :src="img2" v-show="img2" class="webgl-canvas"/>
            <pre><code>const projectMatrix = new Matrix4()
projectMatrix.setOrtho(-1, 1, -1, 1, -1.0, 2.0)</code></pre>
            <p>可视空间设置的足够大，没有再出现未能完整显示的情况：</p>
            <pre><code>最终顶点坐标 = 投影矩阵 * 视图模型矩阵</code></pre>
            <p>使用透视投影矩阵，WebGL会自动将距离远的物体缩小显示，从而产生深度感。使用Matrix4对象的setPerspective()方法来定义透视投影可视空间。</p>
            <pre><code>Matrix4.setPerspective(fov, aspect, near, far)
// fov：垂直视角，可视空间顶面和底面间的夹角，必须大于0
// aspect：近裁剪面的宽高比
// near，far：近裁剪面和远裁剪面的位置，near和far必须大于0</code></pre>
            <canvas ref="canvasRef3" v-show="!img3" class="webgl-canvas"></canvas>
            <img :src="img3" v-show="img3" class="webgl-canvas"/>
            <pre><code>// 视图矩阵
const viewMatrix = new Matrix4()
viewMatrix.setLookAt(0, 0, 5, 0, 0, -100, 0, 1.0, 0)
const projectMatrix = new Matrix4()
const size = window.getComputedStyle(canvasRef.value, null)
// 投影矩阵
projectMatrix.setPerspective(30, parseInt(size.width) / parseInt(size.height), 1, 100)
const matrix = projectMatrix.multiply(viewMatrix)</code></pre>
            <p>顶点坐标的计算公式：</p>
            <pre><code>投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点坐标</code></pre>
            <h3 class="title">隐藏面消除</h3>
            <p>在默认情况下，WebGL为了加速绘图操作，是按照顶点在缓冲区中的顺序来处理的。后绘制的图形将覆盖已经绘制好的图形。</p>
            <canvas ref="canvasRef4" v-show="!img4" class="webgl-canvas"></canvas>
            <img :src="img4" v-show="img4" class="webgl-canvas"/>
            <p>调整三角形顶点的位置，本该出现在最远处的绿色三角形，挡住了近处的黄色和蓝色三角形。WebGL提供了隐藏面消除功能，这个功能可以消除那些被遮挡的表面，可以放心地绘制场景而不必顾及各物体在缓冲区中的顺序：</p>
            <pre><code>// 1.开启隐藏面消除功能
gl.enable(gl.DEPTH_TEST); // gl.DEPTH_TEST、gl.BLEND(混合)、gl.POLYGON_OFFSET_FILL(多边形位移)
// 2.在绘制前，清除深度缓冲区
gl.clear(gl.DEPTH_BUFFER_BIT)</code></pre>
            <p>深度缓冲区是一个中间对象，用来存储深度信息，其作用是帮助WebGL进行隐藏面消除，也称为Z缓存区。</p>
            <pre><code>const gl = el.getContext('webgl2')
gl.enable(gl.DEPTH_TEST)
......
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // 清空颜色和深度缓冲区，每一帧绘制之前，都需要清空深度缓存区。
gl.drawArrays(gl.TRIANGLES, 0, n)</code></pre>
            <p>启用隐藏面消除：</p>
            <canvas ref="canvasRef5" v-show="!img5" class="webgl-canvas"></canvas>
            <img :src="img5" v-show="img5" class="webgl-canvas"/>
            <h3 class="title">深度冲突</h3>
            <p>当物体表面过于接近时，深度缓冲区有限的精度已经不能区分哪个在前，哪个在后了。使用多边形偏移机制可以解决该问题，该机制将自动在Z值加上一个偏移量，偏移量的值由物体表面相对于观察者视线的角度来确定。</p>
            <p>将6个三角形的Z值改成一样：</p>
            <canvas ref="canvasRef6" v-show="!img6" class="webgl-canvas"></canvas>
            <img :src="img6" v-show="img6" class="webgl-canvas"/>
            <pre><code>// 1.启用多边形偏移
gl.enable(gl.POLYGON_OFFSET_FILL);
// 2.指定用来计算偏移量的参数
gl.polygonOffset(factor, units);</code></pre>
            <p>启用之后，效果好像不太明显：</p>
            <canvas ref="canvasRef7" v-show="!img7" class="webgl-canvas"></canvas>
            <img :src="img7" v-show="img7" class="webgl-canvas"/>
            <h3 class="title">立方体的绘制</h3>
            <p>使用gl.drawElements()代替gl.drawArrays()进行绘制，能够避免重复定义顶点，保持顶点数量最小。</p>
            <pre><code>gl.drawElements(mode, count, type, offset) // 执行着色器，按照mode参数指定的方式，根据绑定到gl.ELEMENT_ARRAY_BUFFER的缓冲区中的顶点索引值绘制图形。
// mode：指定绘制方式，gl.POINTS、gl.LINES、gl.LINE_STRIP、gl.LINE_LOOP、gl.TRIANGLES、gl.TRIANGLE_STRIP、gl.TRIANGLE_FAN
// count：指定绘制顶点的个数
// type：指定索引值数据类型，gl.UNSIGNED_BYTE或者gl.UNSIGNED_SHORT
// offset：指定索引数组中开始绘制的位置，以字节为单位</code></pre>
            <pre><code>const initVertexBuffers = (gl) => {
    // 创建缓冲区
    const verticeColorBuffer = gl.createBuffer()
    const indexBuffer = gl.createBuffer()
    if (!verticeColorBuffer || !indexBuffer) {
        return -1
    }

    gl.bindBuffer(gl.ARRAY_BUFFER, verticeColorBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, datas, gl.STATIC_DRAW)
    const eleSize = datas.BYTES_PER_ELEMENT

    const aPosition = gl.getAttribLocation(gl.program, 'a_Position')
    gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 6 * eleSize, 0)
    gl.enableVertexAttribArray(aPosition)

    const aColor = gl.getAttribLocation(gl.program, 'a_Color')
    gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, 6 * eleSize, 3 * eleSize)
    gl.enableVertexAttribArray(aColor)

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW)
    return indices.length
}

// 设置视图/变换矩阵
const uMatrix = gl.getUniformLocation(gl.program, 'u_Matrix')
gl.uniformMatrix4fv(uMatrix, false, matrix)

gl.clearColor(0.0, 0.0, 0.0, 1.0)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0)</code></pre>
            <p>顶点颜色已经索引值数据：</p>
            <pre><code>viewMatrix8.setPerspective(30, parseInt(size8.width) / parseInt(size8.height), 1, 100)
viewMatrix8.lookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
const datas4 = new Float32Array([
    1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // v0 White
    -1.0, 1.0, 1.0, 1.0, 0.0, 1.0, // v1 Magenta
    -1.0, -1.0, 1.0, 1.0, 0.0, 0.0, // v2 Red
    1.0, -1.0, 1.0, 1.0, 1.0, 0.0, // v3 Yellow
    1.0, -1.0, -1.0, 0.0, 1.0, 0.0, // v4 Green
    1.0, 1.0, -1.0, 0.0, 1.0, 1.0, // v5 Cyan
    -1.0, 1.0, -1.0, 0.0, 0.0, 1.0, // v6 Blue
    -1.0, -1.0, -1.0, 0.0, 0.0, 0.0 // v7 Black
])
const indices = new Uint8Array([
    0, 1, 2, 0, 2, 3,
    0, 3, 4, 0, 4, 5,
    0, 5, 6, 0, 6, 1,
    1, 6, 7, 1, 7, 2,
    7, 4, 3, 7, 3, 2,
    4, 7, 6, 4, 6, 5
])</code></pre>
            <canvas ref="canvasRef8" v-show="!img8" class="webgl-canvas"></canvas>
            <img :src="img8" v-show="img8" class="webgl-canvas"/>
            <p>在调用gl.drawElements()时，WebGL首先从绑定到gl.ELEMENT_ARRAY_BUFFER的缓冲区中获取顶点的索引值，然后根据该索引值，从绑定到gl.ARRAY_BUFFER的缓冲区中获取顶点的坐标、颜色等信息，然后传递给attribute变量执行顶点着色器。这种方式通过索引来访问数据，从而循环利用顶点信息，控制内存开销。</p>
            <p>每个面单一颜色的立方体：</p>
            <canvas ref="canvasRef9" v-show="!img9" class="webgl-canvas"></canvas>
            <img :src="img9" v-show="img9" class="webgl-canvas"/>
            <p>需要使用24个顶点，每个面四个顶点设置成一致的颜色值：</p>
            <pre><code>const datas = new Float32Array([
    1.0, 1.0, 1.0, 0.4, 0.4, 1.0, // front
    -1.0, 1.0, 1.0, 0.4, 0.4, 1.0,
    -1.0, -1.0, 1.0, 0.4, 0.4, 1.0,
    1.0, -1.0, 1.0, 0.4, 0.4, 1.0,

    1.0, 1.0, 1.0, 0.4, 1.0, 0.4, // right
    1.0, -1.0, 1.0, 0.4, 1.0, 0.4,
    1.0, -1.0, -1.0, 0.4, 1.0, 0.4,
    1.0, 1.0, -1.0, 0.4, 1.0, 0.4,

    1.0, 1.0, 1.0, 1.0, 0.4, 0.4, // up
    1.0, 1.0, -1.0, 1.0, 0.4, 0.4,
    -1.0, 1.0, -1.0, 1.0, 0.4, 0.4,
    -1.0, 1.0, 1.0, 1.0, 0.4, 0.4,

    -1.0, 1.0, 1.0, 1.0, 1.0, 0.4, // left
    -1.0, 1.0, -1.0, 1.0, 1.0, 0.4,
    -1.0, -1.0, -1.0, 1.0, 1.0, 0.4,
    -1.0, -1.0, 1.0, 1.0, 1.0, 0.4,

    -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, // down
    1.0, -1.0, -1.0, 1.0, 1.0, 1.0,
    1.0, -1.0, 1.0, 1.0, 1.0, 1.0,
    -1.0, -1.0, 1.0, 1.0, 1.0, 1.0,

    1.0, -1.0, -1.0, 0.4, 1.0, 1.0, // back
    -1.0, -1.0, -1.0, 0.4, 1.0, 1.0,
    -1.0, 1.0, -1.0, 0.4, 1.0, 1.0,
    1.0, 1.0, -1.0, 0.4, 1.0, 1.0
])
const indices = new Uint8Array([
    0, 1, 2, 0, 2, 3,
    4, 5, 6, 4, 6, 7,
    8, 9, 10, 8, 10, 11,
    12, 13, 14, 12, 14, 15,
    16, 17, 18, 16, 18, 19,
    20, 21, 22, 20, 22, 23
])</code></pre>
        </div>
    </MyArticle>
</template>

<script>
import { onMounted, ref, onBeforeUnmount } from 'vue'
import Draw0 from './draw0'
import Draw1 from './draw1'
import CuonMatrix4 from './cuonMatrix'

export default {
    setup () {
        const canvasRef0 = ref(null)
        const img0 = ref(null)
        const canvasRef1 = ref(null)
        const img1 = ref(null)
        let ani0 = null
        const canvasRef2 = ref(null)
        const img2 = ref(null)
        let ani1 = null
        const canvasRef3 = ref(null)
        const img3 = ref(null)
        const canvasRef4 = ref(null)
        const img4 = ref(null)
        const canvasRef5 = ref(null)
        const img5 = ref(null)
        const canvasRef6 = ref(null)
        const img6 = ref(null)
        const canvasRef7 = ref(null)
        const img7 = ref(null)
        const canvasRef8 = ref(null)
        const img8 = ref(null)
        let ani8 = null
        const canvasRef9 = ref(null)
        const img9 = ref(null)
        let ani9 = null
        onMounted(() => {
            // ----------------------------------------0.视图矩阵的应用
            const viewMatrix0 = new CuonMatrix4()
            viewMatrix0.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1.0, 0)
            const datas0 = new Float32Array([
                0.0, 0.5, -0.4, 0.4, 1.0, 0.4,
                -0.5, -0.5, -0.4, 0.4, 1.0, 0.4,
                0.5, -0.5, -0.4, 1.0, 0.4, 0.4,

                0.5, 0.4, -0.2, 1.0, 0.4, 0.4,
                -0.5, 0.4, -0.2, 1.0, 1.0, 0.4,
                0.0, -0.6, -0.2, 1.0, 1.0, 0.4,

                0.0, 0.5, 0.0, 0.4, 0.4, 1.0,
                -0.5, -0.5, 0.0, 0.4, 0.4, 1.0,
                0.5, -0.5, 0.0, 1.0, 0.4, 0.4
            ])
            img0.value = (new Draw0(canvasRef0.value, datas0, 9, viewMatrix0.elements)).img

            // ----------------------------------------1.模型视图矩阵的应用
            const rotateStep = 15.0 // 旋转速度
            let currAngle = 0
            let currTime = Date.now()

            let viewMatrix1 = new CuonMatrix4()
            viewMatrix1.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1.0, 0)
            const modelMatrix1 = new CuonMatrix4()
            modelMatrix1.setRotate(currAngle, 0, 0, 1) // 旋转矩阵
            const modelViewMatrix1 = viewMatrix1.multiply(modelMatrix1)
            const draw1 = new Draw0(canvasRef1.value, datas0, 9, modelViewMatrix1.elements)
            img1.value = draw1.img

            const ani0Update = () => {
                const now = Date.now()
                currAngle = (currAngle + (rotateStep * (now - currTime)) / 1000) % 360
                currTime = now
                viewMatrix1 = new CuonMatrix4()
                viewMatrix1.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1.0, 0)
                modelMatrix1.setRotate(currAngle, 0, 0, 1)
                draw1.redraw(viewMatrix1.multiply(modelMatrix1).elements)
                img1.value = draw1.img
                ani0 = requestAnimationFrame(ani0Update)
            }
            ani0 = requestAnimationFrame(ani0Update)

            // ----------------------------------------2.盒状可视空间
            let currAngle1 = 0
            let currTime1 = Date.now()
            let viewMatrix2 = new CuonMatrix4()
            viewMatrix2.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1.0, 0)
            const modelMatrix2 = new CuonMatrix4()
            modelMatrix2.setRotate(currAngle1, 0, 0, 1) // 旋转矩阵
            let modelViewMatrix2 = viewMatrix2.multiply(modelMatrix2)
            let projectMatrix2 = new CuonMatrix4()
            projectMatrix2.setOrtho(-1, 1, -1, 1, -1.0, 2.0)
            const matrix2 = projectMatrix2.multiply(modelViewMatrix2)
            const draw2 = new Draw0(canvasRef2.value, datas0, 9, matrix2.elements)
            img2.value = draw2.img

            const ani1Update = () => {
                const now = Date.now()
                currAngle1 = (currAngle1 + (rotateStep * (now - currTime1)) / 1000) % 360
                currTime1 = now
                viewMatrix2 = new CuonMatrix4()
                modelMatrix2.setRotate(currAngle1, 0, 0, 1)
                viewMatrix2.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1.0, 0)
                modelViewMatrix2 = viewMatrix2.multiply(modelMatrix2)
                projectMatrix2 = new CuonMatrix4()
                projectMatrix2.setOrtho(-1, 1, -1, 1, -1.0, 2.0)
                draw2.redraw(projectMatrix2.multiply(modelViewMatrix2).elements)
                img2.value = draw2.img
                ani1 = requestAnimationFrame(ani1Update)
            }
            ani1 = requestAnimationFrame(ani1Update)

            // ----------------------------------------3.透视投影
            const datas1 = new Float32Array([
                0.75, 1.0, -4.0, 0.4, 1.0, 0.4,
                0.25, -1.0, -4.0, 0.4, 1.0, 0.4,
                1.25, -1.0, -4.0, 1.0, 0.4, 0.4,

                0.75, 1.0, -2.0, 1.0, 1.0, 0.4,
                0.25, -1.0, -2.0, 1.0, 1.0, 0.4,
                1.25, -1.0, -2.0, 1.0, 0.4, 0.4,

                0.75, 1.0, 0.0, 0.4, 0.4, 1.0,
                0.25, -1.0, 0.0, 0.4, 0.4, 1.0,
                1.25, -1.0, 0.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, -4.0, 0.4, 1.0, 0.4,
                -1.25, -1.0, -4.0, 0.4, 1.0, 0.4,
                -0.25, -1.0, -4.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, -2.0, 1.0, 1.0, 0.4,
                -1.25, -1.0, -2.0, 1.0, 1.0, 0.4,
                -0.25, -1.0, -2.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, 0.0, 0.4, 0.4, 1.0,
                -1.25, -1.0, 0.0, 0.4, 0.4, 1.0,
                -0.25, -1.0, 0.0, 1.0, 0.4, 0.4
            ])
            const viewMatrix3 = new CuonMatrix4()
            viewMatrix3.setLookAt(0, 0, 5, 0, 0, -100, 0, 1.0, 0)
            const projectMatrix3 = new CuonMatrix4()
            const size = window.getComputedStyle(canvasRef3.value, null)
            projectMatrix3.setPerspective(30, parseInt(size.width) / parseInt(size.height), 1, 100)
            const matrix3 = projectMatrix3.multiply(viewMatrix3)
            const draw3 = new Draw0(canvasRef3.value, datas1, 18, matrix3.elements)
            img3.value = draw3.img

            // ----------------------------------------4.隐藏面消除
            const datas2 = new Float32Array([
                0.75, 1.0, 0.0, 0.4, 0.4, 1.0,
                0.25, -1.0, 0.0, 0.4, 0.4, 1.0,
                1.25, -1.0, 0.0, 1.0, 0.4, 0.4,

                0.75, 1.0, -2.0, 1.0, 1.0, 0.4,
                0.25, -1.0, -2.0, 1.0, 1.0, 0.4,
                1.25, -1.0, -2.0, 1.0, 0.4, 0.4,

                0.75, 1.0, -4.0, 0.4, 1.0, 0.4,
                0.25, -1.0, -4.0, 0.4, 1.0, 0.4,
                1.25, -1.0, -4.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, 0.0, 0.4, 0.4, 1.0,
                -1.25, -1.0, 0.0, 0.4, 0.4, 1.0,
                -0.25, -1.0, 0.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, -2.0, 1.0, 1.0, 0.4,
                -1.25, -1.0, -2.0, 1.0, 1.0, 0.4,
                -0.25, -1.0, -2.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, -4.0, 0.4, 1.0, 0.4,
                -1.25, -1.0, -4.0, 0.4, 1.0, 0.4,
                -0.25, -1.0, -4.0, 1.0, 0.4, 0.4
            ])
            const viewMatrix4 = new CuonMatrix4()
            viewMatrix4.setLookAt(0, 0, 5, 0, 0, -100, 0, 1.0, 0)
            const projectMatrix4 = new CuonMatrix4()
            const size4 = window.getComputedStyle(canvasRef4.value, null)
            projectMatrix4.setPerspective(30, parseInt(size4.width) / parseInt(size4.height), 1, 100)
            const matrix4 = projectMatrix4.multiply(viewMatrix4)
            const draw4 = new Draw0(canvasRef4.value, datas2, 18, matrix4.elements, false)
            img4.value = draw4.img

            const viewMatrix5 = new CuonMatrix4()
            viewMatrix5.setLookAt(0, 0, 5, 0, 0, -100, 0, 1.0, 0)
            const projectMatrix5 = new CuonMatrix4()
            const size5 = window.getComputedStyle(canvasRef5.value, null)
            projectMatrix5.setPerspective(30, parseInt(size5.width) / parseInt(size5.height), 1, 100)
            const matrix5 = projectMatrix5.multiply(viewMatrix5)
            const draw5 = new Draw0(canvasRef5.value, datas2, 18, matrix5.elements, true)
            img5.value = draw5.img

            // ----------------------------------------5.深度冲突
            const datas3 = new Float32Array([
                0.75, 1.0, -3.0, 0.4, 0.4, 1.0,
                0.25, -1.0, -3.0, 0.4, 0.4, 1.0,
                1.25, -1.0, -3.0, 1.0, 0.4, 0.4,

                0.75, 1.0, -3.0, 1.0, 1.0, 0.4,
                0.25, -1.0, -3.0, 1.0, 1.0, 0.4,
                1.25, -1.0, -3.0, 1.0, 0.4, 0.4,

                0.75, 1.0, -3.0, 0.4, 1.0, 0.4,
                0.25, -1.0, -3.0, 0.4, 1.0, 0.4,
                1.25, -1.0, -3.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, -3.0, 0.4, 0.4, 1.0,
                -1.25, -1.0, -3.0, 0.4, 0.4, 1.0,
                -0.25, -1.0, -3.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, -3.0, 1.0, 1.0, 0.4,
                -1.25, -1.0, -3.0, 1.0, 1.0, 0.4,
                -0.25, -1.0, -3.0, 1.0, 0.4, 0.4,

                -0.75, 1.0, -3.0, 0.4, 1.0, 0.4,
                -1.25, -1.0, -3.0, 0.4, 1.0, 0.4,
                -0.25, -1.0, -3.0, 1.0, 0.4, 0.4
            ])
            const viewMatrix6 = new CuonMatrix4()
            viewMatrix6.setLookAt(0, 0, 5, 0, 0, -100, 0, 1.0, 0)
            const projectMatrix6 = new CuonMatrix4()
            const size6 = window.getComputedStyle(canvasRef6.value, null)
            projectMatrix6.setPerspective(30, parseInt(size6.width) / parseInt(size6.height), 1, 100)
            const matrix6 = projectMatrix6.multiply(viewMatrix6)
            const draw6 = new Draw0(canvasRef6.value, datas3, 18, matrix6.elements, true)
            img6.value = draw6.img

            const viewMatrix7 = new CuonMatrix4()
            viewMatrix7.setLookAt(0, 0, 5, 0, 0, -100, 0, 1.0, 0)
            const projectMatrix7 = new CuonMatrix4()
            const size7 = window.getComputedStyle(canvasRef7.value, null)
            projectMatrix7.setPerspective(30, parseInt(size7.width) / parseInt(size7.height), 1, 100)
            const matrix7 = projectMatrix7.multiply(viewMatrix6)
            const draw7 = new Draw0(canvasRef7.value, datas3, 18, matrix7.elements, true, true)
            img7.value = draw7.img

            // ----------------------------------------8.绘制立方体
            let currAngle8 = 0
            let currTime8 = Date.now()
            let viewMatrix8 = new CuonMatrix4()
            viewMatrix8.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
            const modelMatrix8 = new CuonMatrix4()
            modelMatrix8.setRotate(currAngle8, 0, 0, 1)
            let modelViewMatrix8 = viewMatrix8.multiply(modelMatrix8)
            let projectMatrix8 = new CuonMatrix4()
            const size8 = window.getComputedStyle(canvasRef8.value, null)
            const ratio8 = parseInt(size8.width) / parseInt(size8.height)
            projectMatrix8.setPerspective(30, ratio8, 1, 100)
            const datas4 = new Float32Array([
                1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // v0 White
                -1.0, 1.0, 1.0, 1.0, 0.0, 1.0, // v1 Magenta
                -1.0, -1.0, 1.0, 1.0, 0.0, 0.0, // v2 Red
                1.0, -1.0, 1.0, 1.0, 1.0, 0.0, // v3 Yellow
                1.0, -1.0, -1.0, 0.0, 1.0, 0.0, // v4 Green
                1.0, 1.0, -1.0, 0.0, 1.0, 1.0, // v5 Cyan
                -1.0, 1.0, -1.0, 0.0, 0.0, 1.0, // v6 Blue
                -1.0, -1.0, -1.0, 0.0, 0.0, 0.0 // v7 Black
            ])
            const indices8 = new Uint8Array([
                0, 1, 2, 0, 2, 3,
                0, 3, 4, 0, 4, 5,
                0, 5, 6, 0, 6, 1,
                1, 6, 7, 1, 7, 2,
                7, 4, 3, 7, 3, 2,
                4, 7, 6, 4, 6, 5
            ])
            const draw8 = new Draw1(canvasRef8.value, datas4, indices8, projectMatrix8.multiply(modelViewMatrix8).elements)
            img8.value = draw8.img

            const ani8Update = () => {
                const now = Date.now()
                currAngle8 = (currAngle8 + (rotateStep * (now - currTime8)) / 1000) % 360
                currTime8 = now
                viewMatrix8 = new CuonMatrix4()
                viewMatrix8.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
                modelMatrix8.setRotate(currAngle8, 0, 0, 1)
                modelViewMatrix8 = viewMatrix8.multiply(modelMatrix8)
                projectMatrix8 = new CuonMatrix4()
                projectMatrix8.setPerspective(30, ratio8, 1, 100)
                draw8.redraw(projectMatrix8.multiply(modelViewMatrix8).elements)
                img8.value = draw8.img
                ani8 = requestAnimationFrame(ani8Update)
            }
            ani8 = requestAnimationFrame(ani8Update)

            // ----------------------------------------9.单一颜色的立方体
            let currAngle9 = 0
            let currTime9 = Date.now()
            let viewMatrix9 = new CuonMatrix4()
            viewMatrix9.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
            const modelMatrix9 = new CuonMatrix4()
            modelMatrix9.setRotate(currAngle9, 0, 0, 1)
            let modelViewMatrix9 = viewMatrix9.multiply(modelMatrix9)
            let projectMatrix9 = new CuonMatrix4()
            const size9 = window.getComputedStyle(canvasRef9.value, null)
            const ratio9 = parseInt(size9.width) / parseInt(size9.height)
            projectMatrix9.setPerspective(30, ratio9, 1, 100)
            const datas5 = new Float32Array([
                1.0, 1.0, 1.0, 0.4, 0.4, 1.0, // front
                -1.0, 1.0, 1.0, 0.4, 0.4, 1.0,
                -1.0, -1.0, 1.0, 0.4, 0.4, 1.0,
                1.0, -1.0, 1.0, 0.4, 0.4, 1.0,

                1.0, 1.0, 1.0, 0.4, 1.0, 0.4, // right
                1.0, -1.0, 1.0, 0.4, 1.0, 0.4,
                1.0, -1.0, -1.0, 0.4, 1.0, 0.4,
                1.0, 1.0, -1.0, 0.4, 1.0, 0.4,

                1.0, 1.0, 1.0, 1.0, 0.4, 0.4, // up
                1.0, 1.0, -1.0, 1.0, 0.4, 0.4,
                -1.0, 1.0, -1.0, 1.0, 0.4, 0.4,
                -1.0, 1.0, 1.0, 1.0, 0.4, 0.4,

                -1.0, 1.0, 1.0, 1.0, 1.0, 0.4, // left
                -1.0, 1.0, -1.0, 1.0, 1.0, 0.4,
                -1.0, -1.0, -1.0, 1.0, 1.0, 0.4,
                -1.0, -1.0, 1.0, 1.0, 1.0, 0.4,

                -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, // down
                1.0, -1.0, -1.0, 1.0, 1.0, 1.0,
                1.0, -1.0, 1.0, 1.0, 1.0, 1.0,
                -1.0, -1.0, 1.0, 1.0, 1.0, 1.0,

                1.0, -1.0, -1.0, 0.4, 1.0, 1.0, // back
                -1.0, -1.0, -1.0, 0.4, 1.0, 1.0,
                -1.0, 1.0, -1.0, 0.4, 1.0, 1.0,
                1.0, 1.0, -1.0, 0.4, 1.0, 1.0
            ])
            const indices9 = new Uint8Array([
                0, 1, 2, 0, 2, 3,
                4, 5, 6, 4, 6, 7,
                8, 9, 10, 8, 10, 11,
                12, 13, 14, 12, 14, 15,
                16, 17, 18, 16, 18, 19,
                20, 21, 22, 20, 22, 23
            ])
            const draw9 = new Draw1(canvasRef9.value, datas5, indices9, projectMatrix9.multiply(modelViewMatrix9).elements)
            img9.value = draw9.img

            const ani9Update = () => {
                const now = Date.now()
                currAngle9 = (currAngle9 + (rotateStep * (now - currTime9)) / 1000) % 360
                currTime9 = now
                viewMatrix9 = new CuonMatrix4()
                viewMatrix9.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
                modelMatrix9.setRotate(currAngle9, 0, 0, 1)
                modelViewMatrix9 = viewMatrix9.multiply(modelMatrix9)
                projectMatrix9 = new CuonMatrix4()
                projectMatrix9.setPerspective(30, ratio9, 1, 100)
                draw9.redraw(projectMatrix9.multiply(modelViewMatrix9).elements)
                img9.value = draw9.img
                ani9 = requestAnimationFrame(ani9Update)
            }
            ani9 = requestAnimationFrame(ani9Update)
        })

        onBeforeUnmount(() => {
            if (ani0) {
                cancelAnimationFrame(ani0)
            }
            if (ani1) {
                cancelAnimationFrame(ani1)
            }
            if (ani8) {
                cancelAnimationFrame(ani8)
            }
            if (ani9) {
                cancelAnimationFrame(ani9)
            }
        })

        return {
            canvasRef0,
            img0,
            canvasRef1,
            img1,
            canvasRef2,
            img2,
            canvasRef3,
            img3,
            canvasRef4,
            img4,
            canvasRef5,
            img5,
            canvasRef6,
            img6,
            canvasRef7,
            img7,
            canvasRef8,
            img8,
            canvasRef9,
            img9
        }
    }
}
</script>

<style lang="scss">
    @use "./style.scss";
</style>
